home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
348_01
/
z80a.c
< prev
next >
Wrap
Text File
|
1991-04-30
|
23KB
|
961 lines
/*
This file contains the main program and line assembly routines for the
assembler. The main program parses the command line, feeds the source lines
to the line assembly routine, and sends the results to the listing and object
file output routines. It also coordinates the activities of everything. The
line assembly routine uses the expression analyzer and the lexical analyzer to
parse the source line convert it into the object bytes that it represents.
*/
#define YES 1
#define NO 0
/* Get global goodies: */
#include "z80a.h"
/* Define global mailboxes for all modules: */
char errcode, line[MAXLINE + 1], title[MAXLINE], sub_tit[MAXLINE];
int pass = 0;
int code = TRUE;
int listok = TRUE;
int eject, filesp, forwd, listhex;
unsigned address, bytes, errors, listleft, obj[MAXLINE], pc;
unsigned pagelen = 60;
FILE *filestk[FILES], *source;
TOKEN token;
/* Mainline routine. This routine parses the command line, sets up */
/* the assembler at the beginning of each pass, feeds the source text */
/* to the line assembler, feeds the result to the listing and hex file */
/* drivers, and cleans everything up at the end of the run. */
static int done, ifsp, off;
main(argc,argv)
int argc;
char **argv;
{
SCRATCH unsigned *o;
int newline();
void asm_line();
void lclose(), lopen(), lputs();
void hclose(), hopen(), hputc();
void error_s(), fatal_error(), warning();
printf("Z80 Cross-Assembler (Portable Z80ASM version) Ver 0.0\n");
printf("Copyright (c) 1988 Michael G. Panas\n\n");
while (--argc) {
if (**++argv == '-') {
switch (toupper(*++*argv)) {
case 'L': if (!*++*argv) {
if (!--argc) { warning(NOLST); break; }
else ++argv;
}
lopen(*argv);
break;
case 'O': if (!*++*argv) {
if (!--argc) { warning(NOHEX); break; }
else ++argv;
}
hopen(*argv);
break;
default: warning(BADOPT);
}
}
else if (filestk[0]) warning(TWOASM);
else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
}
if (!filestk[0]) fatal_error(NOASM);
while (++pass < 3) {
fseek(source = filestk[0],0L,0); done = off = FALSE;
errors = filesp = ifsp = pc = 0; title[0] = '\0';
while (!done) {
errcode = ' ';
if (newline()) {
error_s('*');
strcpy(line,"\tEND\n");
done = eject = TRUE; listhex = FALSE;
bytes = 0;
}
else asm_line();
pc = word(pc + bytes);
if (pass == 2) {
lputs();
for (o = obj; bytes--; hputc(*o++));
}
}
}
fclose(filestk[0]); lclose(); hclose();
if (errors) printf("%d Error(s)\n",errors);
else printf("No Errors\n");
exit(errors);
}
/* Line assembly routine. This routine gets expressions and tokens */
/* from the source file using the expression evaluator and lexical */
/* analyzer, respectively. It fills a buffer with the machine code */
/* bytes and returns nothing. */
static char label[MAXLINE];
static int ifstack[IFDEPTH] = { ON };
static OPCODE *opcod;
void asm_line()
{
SCRATCH int i;
int isalph(), popc();
OPCODE *find_code(), *find_operator();
void do_label(), flush(), normal_op(), pseudo_op();
void error_s(), pops(), pushc(), trash(), trash_lex();
#ifdef MICROSOFT_C
void put_len(unsigned);
#else
void put_len();
#endif
address = pc; bytes = 0; eject = forwd = listhex = FALSE;
for (i = 0; i < BIGINST; obj[i++] = NOP);
label[0] = '\0';
if ((i = popc()) != ' ' && i != '\n') {
if (isalph(i)) {
pushc(i); pops(label);
if (find_operator(label)) { label[0] = '\0'; error_s('L'); }
}
else {
error_s('L');
while ((i = popc()) != ' ' && i != '\n');
}
}
trash(); opcod = NULL;
if ((i = popc()) != '\n') {
if (!isalph(i)) error_s('S');
else {
pushc(i); pops(token.sval);
if (!(opcod = find_code(token.sval))) error_s('O');
}
if (!opcod) { listhex = TRUE; bytes = BIGINST; }
}
if (opcod && opcod -> attr & ISIF) { if (label[0]) error_s('L'); }
else if (off) { listhex = FALSE; flush(); return; }
if (!opcod) { do_label(); flush(); }
else {
listhex = TRUE;
trash_lex(); /* space allowed here - don't eat '*' */
if (opcod -> attr & PSEUDO) {
pseudo_op();
if (bytes) put_len(bytes);
} else {
normal_op();
put_len(0);
}
flush(); /* throw rest of line away */
}
source = filestk[filesp];
return;
}
static void flush()
{
while (popc() != '\n');
}
static void do_label()
{
SCRATCH SYMBOL *l;
unsigned pin, st;
SYMBOL *find_symbol(), *new_symbol();
void error_s();
if (label[0]) {
listhex = TRUE;
if (label[0] == '@') {
pin = PIN;
st = 1;
} else {
pin = st = 0;
}
if (pass == 1) {
if (!((l = new_symbol(&label[st])) -> attr)) {
l -> attr = FORWD + VAL + pin;
l -> valu = pc;
l -> len = 2; /* preset length */
}
}
else {
if (l = find_symbol(&label[st])) {
l -> attr = VAL + pin;
if (l -> valu != pc) error_s('M');
}
else error_s('P');
}
}
}
static void put_len(length)
unsigned length;
{
unsigned st = 0;
SCRATCH SYMBOL *l;
SYMBOL *find_symbol();
if (label[0]) {
if (label[0] == '@') st = 1;
if (l = find_symbol(&label[st])) {
l -> len = length;
}
}
}
static void put_attr(attrv)
unsigned attrv;
{
unsigned st = 0;
SCRATCH SYMBOL *l;
SYMBOL *find_symbol();
if (label[0]) {
if (label[0] == '@') st = 1;
if (l = find_symbol(&label[st])) {
l -> attr |= attrv;
}
}
}
unsigned get_len(sym)
char *sym;
{
SCRATCH SYMBOL *l;
SYMBOL *find_symbol();
if (pass == 1) return 1;
if (l = find_symbol(sym)) {
if (l -> len == 0) return 2;
return l -> len;
}
return 0;
}
static void normal_op()
{
SCRATCH unsigned t, opcode, op, left, index, long_op;
int grab_comma();
unsigned expr(), grab_index();
TOKEN *lex(), *lex_op();
void do_label(), error_s(), s_error(), unlex();
opcode = opcod -> valu;
do_label();
left = ((opcod -> attr & SHIFT) >> 8);
long_op = NO;
switch (opcod -> attr & OPTYPE) {
case NO_ARG:
bytes = 1;
break;
case NO_ARG_L: long_op = YES;
bytes = 2;
break;
case ONE_ARG: /* all 8 bit IMM mode instuctions */
if (left) { /* LDI case */
op = (lex() -> valu);
switch (token.attr & TYPE) {
case MIX:
case REG: break;
default: goto error;
}
if (token.attr & INDEX) { /* IX or IY */
opcode += ((op << 8)+0x30); /* set prefix */
if (grab_comma()) goto error;
op = grab_index();
/* SEP eaten by grab_index() */
op += (expr() & 0xff) << 8;
long_op = YES;
bytes = 4;
break;
}
if (grab_sep()) goto error; /* no semicolon */
opcode += (op << left);
}
op = expr();
bytes = 2;
break;
case ONE_ARG_L: /* opcode is one or two bytes with arg */
/* JUMPI and LDSP only */
op = lex() -> valu;
if ((token.attr & TYPE) != REG) {
goto error;
}
if (token.attr & INDEX) { /* IX or IY */
opcode += (op << 8); /* set prefix */
long_op = YES;
bytes = 2;
break;
}
if (op != HL) goto error; /* only HL allowed */
bytes = 1;
break;
case ONE_ARG_L2: /* opcode is two bytes with arg type 2 */
/* ADCHL, ADDIY, ADDIX, SBCHL only */
op = lex() -> valu;
if ((token.attr & TYPE) != REG) {
goto error;
}
switch (op) {
case BC: op = 0; break;
case DE: op = 1; break;
case X: op = 2;
if (opcode != 0xdd09) goto error;
break;
case Y: op = 2;
if (opcode != 0xfd09) goto error;
break;
case HL: op = 2;
if (opcode == 0xdd09 || opcode == 0xfd09)
goto error;
break;
case SP: op = 3; break;
default: goto error;
}
opcode += (op << 4);
long_op = YES;
bytes = 2;
break;
case CALL:
case